#include <iostream>
#include "llvm/IR/Value.h"
#include "llvm/IR/IRBuilder.h"


// LLVM在将AST转换为LLVM IR时，通常使用递归下降的方法遍历AST，然后在遍历的过程中创建LLVM IR指令和基本块
// 在遍历AST时，LLVM需要考虑AST节点的类型和语义，以便正确地转换为LLVM IR指令。
// 例如，对于if语句，LLVM需要创建一个条件分支指令，并创建两个基本块来分别表示if和else分支。
// 类似地，对于while循环，LLVM需要创建一个循环基本块，并在循环体中插入相应的LLVM IR指令，以便实现循环。
// 为了实现代码生成，LLVM通常使用访问者（visitor）模式，它允许LLVM通过遍历AST来调用相应的LLVM IR生成函数。
// 访问者模式将AST节点和LLVM IR生成函数分离开来，使得LLVM可以在遍历AST时根据AST节点的类型和语义，调用相应的LLVM IR生成函数，从而生成相应的LLVM IR指令。


//以下是伪代码来演示LLVM是如何遍历AST的，一个简单的示例，用于将一个加法表达式转换为LLVM IR：

// 定义AST节点
class Expr {
public:
    virtual ~Expr() {}
    virtual llvm::Value *codegen() = 0;
};

class BinaryExpr : public Expr {
public:
    BinaryExpr(Expr *lhs, Expr *rhs) : LHS(lhs), RHS(rhs) {}
    virtual llvm::Value *codegen() {
        // 递归生成左子树和右子树的LLVM IR值
        llvm::Value *L = LHS->codegen();
        llvm::Value *R = RHS->codegen();
        // 将左子树和右子树生成的LLVM IR值相加，生成新的LLVM IR值
        return IRBuilder.CreateAdd(L, R, "addtmp");
    }
private:
    Expr *LHS, *RHS;
};

class NumberExpr : public Expr {
public:
    NumberExpr(double val) : Val(val) {}
    virtual llvm::Value *codegen() {
        // 将数字转换为LLVM IR常量值
        return ConstantFP::get(TheContext, APFloat(Val));
    }
private:
    double Val;
};

// 遍历AST，并生成LLVM IR
llvm::Value *Expr::codegen() {
    if (BinaryExpr *BE = dynamic_cast<BinaryExpr *>(this)) {
        return BE->codegen();
    } else if (NumberExpr *NE = dynamic_cast<NumberExpr *>(this)) {
        return NE->codegen();
    }
    // 处理其他类型的AST节点
    return nullptr;
}

// 主函数
int main() {
    // 创建LLVM IR模块和函数
    Module *M = new Module("my module", TheContext);
    Function *F = Function::Create(
            FunctionType::get(Type::getDoubleTy(TheContext), false),
            Function::ExternalLinkage,
            "add",
            M
    );

    // 创建基本块，并将其插入函数中
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(BB);

    // 创建加法表达式
    Expr *E = new BinaryExpr(
            new NumberExpr(1.0),
            new NumberExpr(2.0)
    );

    // 生成LLVM IR
    llvm::Value *V = E->codegen();

    // 创建LLVM IR返回指令，并将其插入基本块中
    Builder.CreateRet(V);

    // 打印生成的LLVM IR
    M->print(outs(), nullptr);

    return 0;
}

